﻿using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading;
using System.IO;
using GT.Ultilities;

namespace GT.Algorithms
{
	public enum Weight
    {
		TFIDF = 0,
		WFIDF = 1,
		NTFIDF = 2
    }
	public class KEA
	{
		#region Constants
		public readonly int THRESHOLD = 10;
		public const double ALPHA = 0.4;
		#endregion
		#region Fields
		private List<string> _sentences;
		
		public event EventHandler<ReportEventArgs> Report;
		public event EventHandler EndConstructGST;
		public event EventHandler EndComputeIDF;
		public event EventHandler EndExtract;
		#endregion
		#region Properties
		public GST GST { get; private set; }
		public List<string> Paths { get; set; }
		public List<Node> Nodes { get; private set; }
		public bool IsConstructing { get; private set; }
		public bool IsComputingIDF { get; private set; }
		public bool IsExtracted { get; private set; }
		#endregion
		#region Constructors
		public KEA()
		{

		}
		public KEA(string content)
		{
            //content = content.ToLower();
            
            //content = Regex.Replace(content, @"[^\w\.!?]", " ");
            //content = Regex.Replace(content, @"[.]+", ".");
            //content = Regex.Replace(content, @"[\s]+", " ");
            this._sentences = new List<string>();
            foreach (string str in content.Split(new char[] { '.', '!', '?' }))
            {
                if (!string.IsNullOrEmpty(str)) this._sentences.Add(str);
            }
            //this._content = content;
            Paths = new List<string>();
		}
        public KEA(string content, int t)
            : this(content)
        {
            THRESHOLD = t;
        }
		#endregion
		#region Methods
		public void ConstructGST()
		{
			new Thread(new ThreadStart(() =>
			{
				this.IsConstructing = true;
				this.Report(this, new ReportEventArgs("Đang tạo cây hậu tố... 0%", 0));
				GST = new GST();
				for (int i = 0; i < this._sentences.Count; i++)
				{
					GST.Add(this._sentences[i]);
					int percentage = (i + 1) * 100 / this._sentences.Count;
					this.Report(this, new ReportEventArgs(string.Format("Đang tạo cây hậu tố... {0}%", percentage), percentage));
				}
				this.IsConstructing = false;
                this.Report(this, new ReportEventArgs("Đang tạo cây hậu tố... 100%", 100));
				EndConstructGST(this, new EventArgs());
			})).Start();
		}
		public void ComputeIDF()
		{
			new Thread(new ThreadStart(() =>
			{
				this.IsComputingIDF = true;
				Nodes = GST.FindFWS(THRESHOLD);
				this.Report(this, new ReportEventArgs("Đang tính IDF... 0%", 0));
				for (int i = 0; i < Paths.Count; i++)
				{
					//IDF idf = new IDF(Paths[i]);
					string ext = Path.GetExtension(Paths[i]).ToLower();
					string text = "";
					switch (ext)
					{
						case ".txt":
							text = File.ReadAllText(Paths[i]).ToLower();
							break;
						case ".docx": text = Docx.Text(Paths[i]).ToLower();
							break;
						case ".pdf":
							text = PDF.Text(Paths[i]).ToLower();
							break;
					}
					for (int j = 0; j < Nodes.Count; j++)
					{
						if (text.IndexOf(Nodes[j].Text) >= 0)
						{
							Nodes[j].NumDocs++;
						}
						//if (idf.Search(Nodes[j].Text)) Nodes[j].NumDocs++;
					}
					int percentage = (i + 1) * 100 / Paths.Count;
					this.Report(this, new ReportEventArgs(string.Format("Đang tính IDF... {0}%", percentage), percentage));
				}
				int maxTF = 0;
				for (int j = 0; j < Nodes.Count; j++)
				{
					maxTF = (maxTF < Nodes[j].TF) ? Nodes[j].TF : maxTF;
				}
				for (int j = 0; j < Nodes.Count; j++)
				{
					Nodes[j].IDF = Math.Log10((Paths.Count + 1) / Nodes[j].NumDocs);
					Nodes[j].TFIDF = (double.IsInfinity(Nodes[j].IDF)) ? 0 : Nodes[j].TF * Nodes[j].IDF;
					Nodes[j].WFIDF = (double.IsInfinity(Nodes[j].IDF)) ? 0 : (1 + Math.Log10(Nodes[j].TF)) * Nodes[j].IDF;
					Nodes[j].NTFIDF = (double.IsInfinity(Nodes[j].IDF)) ? 0 : (ALPHA + (1 - ALPHA)*Nodes[j].TF / maxTF) * Nodes[j].IDF;
				}
				this.IsComputingIDF = false;
                this.Report(this, new ReportEventArgs("Hoàn thành tính IDF... 100%", 100));
				this.EndComputeIDF(this, new EventArgs());
			})).Start();
		}
		public void Extract(Weight w)
		{
			Extract(w, true);
		}
		public void Extract(Weight w, bool use)
		{
			new Thread(new ThreadStart(() =>
			{
				if (use)
				{
					switch (w)
					{
						case Weight.TFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].TFIDF * Nodes[i].Depth < Nodes[j].TFIDF * Nodes[j].Depth)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].TFIDF * Nodes[i].Depth;
							}
							break;
						case Weight.WFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].WFIDF * Nodes[i].Depth < Nodes[j].WFIDF * Nodes[j].Depth)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].WFIDF * Nodes[i].Depth;
							}
							break;
						case Weight.NTFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].NTFIDF * Nodes[i].Depth < Nodes[j].NTFIDF * Nodes[j].Depth)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].NTFIDF * Nodes[i].Depth;
							}
							break;
					}
				}
				else
				{
					switch (w)
					{
						case Weight.TFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].TFIDF < Nodes[j].TFIDF)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].TFIDF;
							}
							break;
						case Weight.WFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].WFIDF < Nodes[j].WFIDF)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].WFIDF;
							}
							break;
						case Weight.NTFIDF:
							for (int i = 0; i < Nodes.Count; i++)
							{
								for (int j = i + 1; j < Nodes.Count; j++)
								{
									if (Nodes[i].NTFIDF < Nodes[j].NTFIDF)
									{
										Node node = Nodes[i];
										Nodes[i] = Nodes[j];
										Nodes[j] = node;
									}
								}
								Nodes[i].Weight = Nodes[i].NTFIDF;
							}
							break;
					}
				}
				this.Report(this, new ReportEventArgs("Hoàn thành việc tìm từ khóa... 100%", 100));
				this.EndExtract(this, new EventArgs());
			})).Start();
		}
		#endregion
	}
}